/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

const bit<8>  TCP_PROTOCOL = 0x06;  // TCP协议类型值
const bit<16> TYPE_IPV4 = 0x800;    // IPv4以太网类型值

// 新增：CPU 头部，用于携带 ECN 信息到控制器
header cpu_t {
    bit<8> ecn;
}

typedef bit<9>  egressSpec_t;  // 出口端口类型
typedef bit<48> macAddr_t;     // MAC地址类型
typedef bit<32> ip4Addr_t;     // IPv4地址类型

header ethernet_t {  // 以太网报头
    macAddr_t dstAddr;   // 目的MAC地址
    macAddr_t srcAddr;   // 源MAC地址
    bit<16>   etherType; // 以太网类型
}

header ipv4_t {  // IPv4报头
    bit<4>    version;       // 版本号
    bit<4>    ihl;           // 报头长度
    bit<6>    diffserv;      // 区分服务字段（原TOS的高6位）
    bit<2>    ecn;           // ECN字段（原TOS的低2位）
    bit<16>   totalLen;      // 总长度
    bit<16>   identification;// 标识
    bit<3>    flags;         // 标志
    bit<13>   fragOffset;    // 分片偏移
    bit<8>    ttl;           // 生存时间
    bit<8>    protocol;      // 上层协议
    bit<16>   hdrChecksum;   // 报头校验和
    ip4Addr_t srcAddr;       // 源IP地址
    ip4Addr_t dstAddr;       // 目的IP地址
}

struct headers {  // 报头集合
    ethernet_t   ethernet;
    cpu_t        cpu;
    ipv4_t       ipv4;
}
struct metadata {  // 元数据结构（暂无内容）
}

/*************************************************************************
*********************** 解析器  ***********************************
*************************************************************************/

parser MyParser(packet_in packet,
                  out headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {

    state start {  // 起始状态
        transition parse_ethernet;  // 跳转到解析以太网报头状态
    }

    state parse_ethernet {  // 解析以太网报头状态
        packet.extract(hdr.ethernet);  // 从数据包中提取以太网报头
        transition select(hdr.ethernet.etherType) {  // 根据以太网类型跳转
            TYPE_IPV4: parse_ipv4;  // 若为IPv4类型，跳转到解析IPv4报头状态
            default: accept;        // 其他类型，接受数据包
        }
    }

    state parse_ipv4 {  // 解析IPv4报头状态
        packet.extract(hdr.ipv4);
        transition accept;
    }
}


/*************************************************************************
************   校验和验证   *************
*************************************************************************/

control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply {  }  // 暂未实现校验和验证
}


/*************************************************************************
**************  入口处理  *******************
*************************************************************************/

control MyIngress(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {
    action drop() {  // 丢弃动作
        mark_to_drop(standard_metadata);  // 标记数据包为丢弃
    }

    action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {  // IPv4转发动作
        standard_metadata.egress_spec = port;  // 设置出口端口
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;  // 更新源MAC地址为原目的MAC
        hdr.ethernet.dstAddr = dstAddr;  // 设置目的MAC地址
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;  // TTL减1
    }

    table ipv4_lpm {  // IPv4最长前缀匹配表
        key = {
            hdr.ipv4.dstAddr: lpm;  // 以目的IPv4地址作为关键字（最长前缀匹配）
        }
        actions = {
            ipv4_forward;  // 转发动作
            drop;          // 丢弃动作
        }
        size = 1024;  // 表大小
        default_action = drop;  // 默认动作：丢弃
    }

    apply {
        if (hdr.ipv4.isValid()) {  // 若IPv4报头有效
            ipv4_lpm.apply();      // 执行IPv4转发查表
        }
    }
}

/*************************************************************************
****************  出口处理  *******************
*************************************************************************/

control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {

    action mark_ecn(bit<19> ecn_threshold) {
        if (standard_metadata.enq_qdepth >= ecn_threshold) {
            hdr.ipv4.ecn = 3;
        }
        // 无论 ECN 值是 1、2 还是 3，都克隆数据包
        clone_preserving_field_list(CloneType.E2E, 100, 0);
    }

    table check_ecn {
        actions = {
            mark_ecn;
            NoAction;
        }
        default_action = NoAction();
    }

    apply {
        // instance_type: NORMAL = 0
        if (standard_metadata.instance_type == 0) {
            if (hdr.ipv4.ecn == 1 || hdr.ipv4.ecn == 2) {
                check_ecn.apply();
            }
        }
        // instance_type: EGRESS_CLONE = 2
        if (standard_metadata.instance_type == 2) {
            hdr.cpu.setValid();
            hdr.cpu.ecn = (bit<8>)hdr.ipv4.ecn;
            truncate((bit<32>)15); // 截取以太网 + cpu 头部部分
        }
    }
  }

/*************************************************************************
*************   校验和计算   **************
*************************************************************************/

control MyComputeChecksum(inout headers hdr, inout metadata meta) {
    apply {
        /* 已完成: 用diffserv和ecn字段替换tos字段 */
        update_checksum(  // 更新校验和
            hdr.ipv4.isValid(),  // 若IPv4报头有效则更新
            { hdr.ipv4.version,
              hdr.ipv4.ihl,
              hdr.ipv4.diffserv,  // 使用拆分后的diffserv
              hdr.ipv4.ecn,       // 使用拆分后的ecn
              hdr.ipv4.totalLen,
              hdr.ipv4.identification,
              hdr.ipv4.flags,
              hdr.ipv4.fragOffset,
              hdr.ipv4.ttl,
              hdr.ipv4.protocol,
              hdr.ipv4.srcAddr,
              hdr.ipv4.dstAddr },  // 参与校验和计算的字段
            hdr.ipv4.hdrChecksum,  // 校验和字段
            HashAlgorithm.csum16); // 16位校验和算法
    }
}

/*************************************************************************
***********************  解解析器  *******************************
*************************************************************************/

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.cpu);  // 直接 emit，无效报头会被自动忽略
        packet.emit(hdr.ipv4);

    }
}

/*************************************************************************
***********************  交换机  *******************************
*************************************************************************/

V1Switch(  // 实例化V1模型交换机
MyParser(),                  // 解析器
MyVerifyChecksum(),          // 校验和验证器
MyIngress(),                 // 入口处理器
MyEgress(),                  // 出口处理器
MyComputeChecksum(),         // 校验和计算器
MyDeparser()                 // 解解析器
) main;  // 主交换机实例
